package com.ruoyi.redis;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MapPropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: LvKinfy
 * @Date: 2019/3/17 22:15
 * @Version 1.0
 * @desc Redis集群配置
 */
@Configuration
public class RedisClusterConfig {
  /**
   * @param clusterNodes
   * @param timeout
   * @param redirects
   * @return
   * @desc RedisCluster参数配置
   */
  @Bean
  @ConditionalOnMissingBean(name = "clusterConfig")
  public RedisClusterConfiguration clusterConfig(@Value("${spring.redis.cluster.nodes}") String clusterNodes, @Value("${spring.redis.timeout}") Long timeout, @Value("${spring.redis.cluster.max-redirects}") int redirects) {
    Map<String, Object> source = new HashMap<>();
    source.put("spring.redis.cluster.nodes", clusterNodes);
    source.put("spring.redis.timeout", timeout);
    source.put("spring.redis.cluster.max-redirects", redirects);
    RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
    clusterConfig.setPassword(RedisPassword.of("impress_redis_900"));
    return clusterConfig;
  }

  /**
   * @param clusterConfig
   * @return
   * @desc 连接池设置
   */
  @Bean
  @ConditionalOnMissingBean(name = "redisConnectionFactory")
  public RedisConnectionFactory getRedisConnectionFactory(@Value("${spring.redis.lettuce.pool.max-idle}") int maxIdle, @Value("${spring.redis.lettuce.pool.max-wait}") int maxWait, @Value("${spring.redis.lettuce.pool.max-active}") int maxTotal, RedisClusterConfiguration clusterConfig) {
    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    config.setMaxIdle(maxIdle);
    config.setMaxTotal(maxTotal);
    config.setMaxWaitMillis(maxWait);
    config.setSoftMinEvictableIdleTimeMillis(1800000L);//对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断  (默认逐出策略)
    //config.setEvictorShutdownTimeoutMillis(10000L);//默认10000L
    //config.setMinEvictableIdleTimeMillis(1800000L);//逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
    //config.setTestOnBorrow(true);//在获取连接的时候检查有效性, 默认false
    //config.setTestWhileIdle(false);//在空闲时检查有效性, 默认false
    config.setBlockWhenExhausted(true);//连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
    config.setTimeBetweenEvictionRunsMillis(160000L);//逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
    return new LettuceConnectionFactory(clusterConfig, LettucePoolingClientConfiguration.builder().poolConfig(config).commandTimeout(Duration.ofMillis(30000)).shutdownTimeout(Duration.ofMillis(10000)).build());
  }

  @Bean
  @ConditionalOnMissingBean(name = "redisTemplate")
  public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    RedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
    RedisSerializer stringSerializer = new StringRedisSerializer();
//        ParserConfig.getGlobalInstance().addAccept("com.meeguo.");
    template.setValueSerializer(fastJsonRedisSerializer);
    template.setKeySerializer(stringSerializer);
    template.setHashKeySerializer(stringSerializer);
    template.setHashValueSerializer(fastJsonRedisSerializer);
    // 设置值（value）的序列化采用FastJsonRedisSerializer
    return template;
  }
}
